From 4589f663862d8e7a062b356db3034992a56ed1c9 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Fri, 17 Jun 2022 17:36:31 +0100
Subject: [PATCH] add support System Realtime and System Common

https://github.com/cchaussat/ttymidi-sysex/pull/2

Add input and output support for MIDI System Common and System Realtime operations.
---
 ttymidi-sysex.c | 194 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 181 insertions(+), 13 deletions(-)

diff --git a/ttymidi-sysex.c b/ttymidi-sysex.c
index ceaeaa9..fc39f49 100644
--- a/ttymidi-sysex.c
+++ b/ttymidi-sysex.c
@@ -338,18 +338,103 @@ void parse_midi_command(snd_seq_t* seq, int port_out_id, unsigned char *buf, int
 			break;
 
 		case 0xF0:  // *new*
-			if (buf[0] == 0xF0) {
-				if (!arguments.silent && arguments.verbose) {
-					printf("Serial  %02X Sysex len = %04X   ", operation, buflen);  // *new*
-					int i;
-					for (i=0; i < buflen; i++) {
-						printf("%02X ", buf[i]);
+			switch (channel) {
+				case 0x0:
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  %02X Sysex len = %04X   ", operation, buflen);  // *new*
+						int i;
+						for (i=0; i < buflen; i++) {
+							printf("%02X ", buf[i]);
+						}
+						printf("\n");
+						fflush(stdout);  // *new*
 					}
-					printf("\n");
-					fflush(stdout);  // *new*
-				}
-				// Send sysex message
-				snd_seq_ev_set_sysex(&ev, buflen, buf);
+					// Send sysex message
+					snd_seq_ev_set_sysex(&ev, buflen, buf);
+					break;
+				case 0x1: // MTC Quarter Frame package
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  MTC Quarter Frame       %02x\n", param1);
+						fflush(stdout);  // *new*
+					}
+					snd_seq_ev_set_fixed(&ev);
+					ev.data.control.value = param1;
+					ev.type = SND_SEQ_EVENT_QFRAME;
+					break;
+				case 0x2: // Song Position
+					int_param1 = (int) (param1 & 0x7F) + ((param2 & 0x7F) << 7);  // *new*
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  Song Position           %04x\n", int_param1);
+						fflush(stdout);  // *new*
+					}
+					snd_seq_ev_set_fixed(&ev);
+					ev.data.control.value = int_param1;
+					ev.type = SND_SEQ_EVENT_SONGPOS;
+					break;
+				case 0x3: // Song Select
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  Song Select             %02x\n", param1);
+						fflush(stdout);  // *new*
+					}
+					snd_seq_ev_set_fixed(&ev);
+					ev.data.control.value = param1;
+					ev.type = SND_SEQ_EVENT_SONGSEL;
+					break;
+				case 0x6: // Tune Request
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  Tune Request\n");
+						fflush(stdout);  // *new*
+					}
+					snd_seq_ev_set_fixed(&ev);
+					ev.type = SND_SEQ_EVENT_TUNE_REQUEST;
+					break;
+				case 0x8: // Clock
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  Clock\n");
+						fflush(stdout);  // *new*
+					}
+					snd_seq_ev_set_fixed(&ev);
+					ev.type = SND_SEQ_EVENT_CLOCK;
+					break;
+				case 0xA: // Start
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  Start\n");
+						fflush(stdout);  // *new*
+					}
+					snd_seq_ev_set_fixed(&ev);
+					ev.type = SND_SEQ_EVENT_START;
+					break;
+				case 0xB: // Continue
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  Continue\n");
+						fflush(stdout);  // *new*
+					}
+					snd_seq_ev_set_fixed(&ev);
+					ev.type = SND_SEQ_EVENT_CONTINUE;
+					break;
+				case 0xC: // Stop
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  Stop\n");
+						fflush(stdout);  // *new*
+					}
+					snd_seq_ev_set_fixed(&ev);
+					ev.type = SND_SEQ_EVENT_STOP;
+					break;
+				case 0xE: // Active sense
+					if (!arguments.silent && arguments.verbose) {
+						printf("Serial  Active sense\n");
+						fflush(stdout);  // *new*
+					}
+					snd_seq_ev_set_fixed(&ev);
+					ev.type = SND_SEQ_EVENT_SENSING;
+					break;
+
+				default:
+					if (!arguments.silent) {  // *new*
+						printf("Serial  %02X Unknown MIDI System cmd\n", buf[0] & 0xFF);  // *new*
+						fflush(stdout);  // *new*
+					}
+					break;
 			}
 			break;
 
@@ -464,6 +549,83 @@ void write_midi_action_to_serial_port(snd_seq_t* seq_handle)
 				}
 				break;
 
+			case SND_SEQ_EVENT_QFRAME:
+				bytes[0] = 0xF1;
+				bytes[1] = ev->data.control.value;
+				if (!arguments.silent && arguments.verbose) {
+					printf("Alsa    %02X MTC Quarter Frame      %02X\n", bytes[0], bytes[1]);
+					fflush(stdout);  // *new*
+				}
+				break;
+
+			case SND_SEQ_EVENT_SONGPOS:
+				bytes[0] = 0xF2;
+				ev->data.control.value += 8192;
+				bytes[1] = (unsigned char)(ev->data.control.value & 0x7F);
+				bytes[2] = (unsigned char)(ev->data.control.value >> 7);
+				if (!arguments.silent && arguments.verbose) {
+					printf("Alsa    %02X Song Position      %04X\n", bytes[0], ev->data.control.value);
+					fflush(stdout);  // *new*
+				}
+				break;
+
+			case SND_SEQ_EVENT_SONGSEL:
+				bytes[0] = 0xF3;
+				bytes[1] = ev->data.control.value;
+				if (!arguments.silent && arguments.verbose) {
+					printf("Alsa    %02X Song Select        %02X\n", bytes[0], bytes[1]);
+					fflush(stdout);  // *new*
+				}
+				break;
+
+			case SND_SEQ_EVENT_TUNE_REQUEST:
+				bytes[0] = 0xF6;
+				if (!arguments.silent && arguments.verbose) {
+					printf("Alsa    %02X Tune Request\n", bytes[0]);
+					fflush(stdout);  // *new*
+				}
+				break;
+
+			case SND_SEQ_EVENT_CLOCK:
+				bytes[0] = 0xF8;
+				if (!arguments.silent && arguments.verbose) {
+					printf("Alsa    %02X Clock\n", bytes[0]);
+					fflush(stdout);  // *new*
+				}
+				break;
+
+			case SND_SEQ_EVENT_START:
+				bytes[0] = 0xFA;
+				if (!arguments.silent && arguments.verbose) {
+					printf("Alsa    %02X Start\n", bytes[0]);
+					fflush(stdout);  // *new*
+				}
+				break;
+
+			case SND_SEQ_EVENT_CONTINUE:
+				bytes[0] = 0xFB;
+				if (!arguments.silent && arguments.verbose) {
+					printf("Alsa    %02X Continue\n", bytes[0]);
+					fflush(stdout);  // *new*
+				}
+				break;
+
+			case SND_SEQ_EVENT_STOP:
+				bytes[0] = 0xFC;
+				if (!arguments.silent && arguments.verbose) {
+					printf("Alsa    %02X Stop\n", bytes[0]);
+					fflush(stdout);  // *new*
+				}
+				break;
+
+			case SND_SEQ_EVENT_SENSING:
+				bytes[0] = 0xFE;
+				if (!arguments.silent && arguments.verbose) {
+					printf("Alsa    %02X Active Sense\n", bytes[0]);
+					fflush(stdout);  // *new*
+				}
+				break;
+
 			default:
 				if (!arguments.silent) {  // *new*
 					printf("Alsa    %02X Unknown MIDI cmd   %02X %02X %02X\n", bytes[0]&0xF0, bytes[0]&0x0F, bytes[1], bytes[2]);  // *new*
@@ -484,8 +646,10 @@ void write_midi_action_to_serial_port(snd_seq_t* seq_handle)
 			if (bytes[0]!=0x00)
 			{
 				bytes[1] = (bytes[1] & 0x7F); // just to be sure that one bit is really zero
-				if (bytes[2]==0xFF) {
+				if (bytes[2]==0xFF || bytes[0]==0xF1 || bytes[0]==0xF3 || bytes[0]==0xF5)
 					write(serial, bytes, 2);
+				else if (bytes[0]==0xF4 || bytes[0]==0xF6 || bytes[0]>=0xF8) {
+					write(serial, bytes, 1);
 				} else {
 					bytes[2] = (bytes[2] & 0x7F);
 					write(serial, bytes, 3);
@@ -570,7 +734,11 @@ void* read_midi_from_serial_port(void* seq)
 					break;
 				}
 				buf[0] = buf[i];
-				if(buf[0] != 0xF0)	//if not SysEx *new*
+				if (buf[0] == 0xF1 || buf[0] == 0xF3 || buf[0] == 0xF5)
+					bytesleft = 1;
+				else if (buf[0] >= 0xF4 || buf[0] >= 0xF6 || (buf[0] >= 0xF8 && buf[0] <= 0xFE))
+					bytesleft = 0;
+				else if (buf[0] != 0xF0)	//if not SysEx *new*
 					bytesleft = 3;
 				i = 1;
 			} else {
